# -*- coding: utf-8 -*-
# Author   : ZhangQing
# Time     : 2025-08-12 11:30
# File     : settings.py
# Project  : codebuddy_craft
# Desc     : 项目配置

"""
项目配置 ⚙️

集中管理项目配置，包括数据库、安全、日志、性能等设置
"""

import os
import json
import logging
from typing import Dict, Any, List, Optional, Set, Union
from pathlib import Path
from functools import lru_cache

from pydantic import Field, validator, AnyHttpUrl
from pydantic_settings import BaseSettings

# 获取项目根目录
ROOT_DIR = Path(__file__).parent.parent.parent.absolute()


class Settings(BaseSettings):
    """项目配置类 ⚙️"""
    
    # 基础配置
    PROJECT_NAME: str = "CodeBuddy Craft"
    PROJECT_VERSION: str = "1.0.0"
    PROJECT_DESCRIPTION: str = "智能代码助手"
    DEBUG: bool = False
    ENVIRONMENT: str = "development"
    
    # 路径配置
    ROOT_DIR: Path = ROOT_DIR
    DATA_DIR: Path = ROOT_DIR / "data"
    LOGS_DIR: Path = ROOT_DIR / "logs"
    TEMP_DIR: Path = ROOT_DIR / "temp"
    
    # API配置
    API_PREFIX: str = "/api"
    API_V1_PREFIX: str = "/api/v1"
    DOCS_URL: str = "/docs"
    REDOC_URL: str = "/redoc"
    OPENAPI_URL: str = "/openapi.json"
    
    # 服务器配置
    HOST: str = "0.0.0.0"
    PORT: int = 8000
    WORKERS: int = 1
    RELOAD: bool = True
    
    # 数据库配置
    DATABASE_URL: str = "sqlite+aiosqlite:///./data/codebuddy.db"
    DATABASE_ECHO: bool = False
    DATABASE_POOL_SIZE: int = 20
    DATABASE_MAX_OVERFLOW: int = 10
    DATABASE_CONNECT_TIMEOUT: int = 30
    
    # 安全配置
    SECRET_KEY: str = "change_this_in_production_environment_32chars"
    ALGORITHM: str = "HS256"
    ACCESS_TOKEN_EXPIRE_MINUTES: int = 60 * 24  # 1天
    REFRESH_TOKEN_EXPIRE_MINUTES: int = 60 * 24 * 7  # 7天
    CORS_ORIGINS: List[AnyHttpUrl] = []
    RATE_LIMIT: int = 60  # 每分钟请求数
    
    # 日志配置
    LOG_LEVEL: str = "INFO"
    LOG_FORMAT: str = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
    LOG_FILE: Optional[str] = None
    LOG_ROTATION: str = "500 MB"
    LOG_RETENTION: str = "10 days"
    LOG_JSON_FORMAT: bool = False
    
    # 审计配置
    AUDIT_ENABLED: bool = True
    AUDIT_BUFFER_SIZE: int = 100
    
    # 缓存配置
    CACHE_URL: Optional[str] = None
    CACHE_PREFIX: str = "codebuddy:"
    CACHE_DEFAULT_TTL: int = 3600  # 1小时
    
    # AI配置
    AI_PROVIDER: str = "openai"
    AI_API_KEY: Optional[str] = None
    AI_MODEL: str = "gpt-4"
    AI_TEMPERATURE: float = 0.7
    AI_MAX_TOKENS: int = 2000
    
    # LLM配置
    LLM_API_KEY: Optional[str] = None
    LLM_API_BASE: str = "https://api.openai.com/v1"
    LLM_MODEL: str = "gpt-4"
    LLM_TIMEOUT: int = 60
    LLM_MAX_RETRIES: int = 3
    LLM_RETRY_DELAY: int = 2
    
    # 文件存储配置
    STORAGE_TYPE: str = "local"  # local, s3, azure
    STORAGE_LOCAL_PATH: Path = DATA_DIR / "files"
    STORAGE_S3_BUCKET: Optional[str] = None
    STORAGE_S3_REGION: Optional[str] = None
    UPLOAD_DIR: Path = DATA_DIR / "uploads"
    
    # 性能配置
    PERFORMANCE_MONITORING: bool = True
    PERFORMANCE_SAMPLE_RATE: float = 0.1  # 10%的请求会被采样
    
    # 邮件配置
    MAIL_ENABLED: bool = False
    MAIL_SERVER: Optional[str] = None
    MAIL_PORT: int = 587
    MAIL_USERNAME: Optional[str] = None
    MAIL_PASSWORD: Optional[str] = None
    MAIL_FROM: Optional[str] = None
    MAIL_FROM_NAME: Optional[str] = None
    MAIL_TLS: bool = True
    MAIL_SSL: bool = False
    ENABLE_EMAIL_VERIFICATION: bool = False
    
    # 通知配置
    NOTIFICATIONS_ENABLED: bool = True
    
    # 前端配置
    FRONTEND_URL: Optional[str] = None
    
    # 验证器
    @validator("CORS_ORIGINS", pre=True)
    def assemble_cors_origins(cls, v: Union[str, List[str]]) -> List[str]:
        """处理CORS来源配置"""
        if isinstance(v, str) and not v.startswith("["):
            return [i.strip() for i in v.split(",")]
        elif isinstance(v, (list, str)):
            return v
        raise ValueError(v)
    
    @validator("DATABASE_URL", pre=True)
    def validate_database_url(cls, v: str) -> str:
        """验证数据库URL"""
        if v.startswith("sqlite://") and not v.startswith("sqlite+aiosqlite://"):
            return v.replace("sqlite://", "sqlite+aiosqlite://")
        return v
    
    @validator("STORAGE_LOCAL_PATH", "UPLOAD_DIR", pre=True)
    def create_storage_path(cls, v: Union[str, Path]) -> Path:
        """确保存储路径存在"""
        path = Path(v)
        path.mkdir(parents=True, exist_ok=True)
        return path
    
    @validator("LOGS_DIR", "DATA_DIR", "TEMP_DIR", pre=True)
    def create_directory(cls, v: Union[str, Path]) -> Path:
        """确保目录存在"""
        path = Path(v)
        path.mkdir(parents=True, exist_ok=True)
        return path
    
    # 属性
    @property
    def is_development(self) -> bool:
        """是否为开发环境"""
        return self.ENVIRONMENT.lower() == "development"
    
    @property
    def is_production(self) -> bool:
        """是否为生产环境"""
        return self.ENVIRONMENT.lower() == "production"
    
    @property
    def is_testing(self) -> bool:
        """是否为测试环境"""
        return self.ENVIRONMENT.lower() == "testing"
    
    # 方法
    def get_log_config(self) -> Dict[str, Any]:
        """获取日志配置"""
        return {
            "version": 1,
            "disable_existing_loggers": False,
            "formatters": {
                "default": {
                    "format": self.LOG_FORMAT,
                    "datefmt": "%Y-%m-%d %H:%M:%S",
                },
                "json": {
                    "()": "pythonjsonlogger.jsonlogger.JsonFormatter",
                    "format": "%(asctime)s %(name)s %(levelname)s %(message)s",
                    "datefmt": "%Y-%m-%d %H:%M:%S",
                },
            },
            "handlers": {
                "console": {
                    "class": "logging.StreamHandler",
                    "formatter": "json" if self.LOG_JSON_FORMAT else "default",
                    "level": self.LOG_LEVEL,
                },
                "file": {
                    "class": "logging.handlers.RotatingFileHandler",
                    "formatter": "json" if self.LOG_JSON_FORMAT else "default",
                    "filename": self.LOG_FILE or str(self.LOGS_DIR / "codebuddy.log"),
                    "maxBytes": 500 * 1024 * 1024,  # 500 MB
                    "backupCount": 10,
                    "level": self.LOG_LEVEL,
                } if self.LOG_FILE or self.is_production else {
                    "class": "logging.NullHandler",
                },
            },
            "loggers": {
                "": {
                    "handlers": ["console", "file"] if (self.LOG_FILE or self.is_production) else ["console"],
                    "level": self.LOG_LEVEL,
                    "propagate": True,
                },
                "uvicorn": {
                    "handlers": ["console", "file"] if (self.LOG_FILE or self.is_production) else ["console"],
                    "level": "INFO",
                    "propagate": False,
                },
                "sqlalchemy": {
                    "handlers": ["console", "file"] if (self.LOG_FILE or self.is_production) else ["console"],
                    "level": "WARNING",
                    "propagate": False,
                },
            },
        }
    
    def get_frontend_config(self) -> Dict[str, Any]:
        """获取前端配置"""
        return {
            "apiUrl": self.API_PREFIX,
            "projectName": self.PROJECT_NAME,
            "projectVersion": self.PROJECT_VERSION,
            "environment": self.ENVIRONMENT,
            "performanceMonitoring": self.PERFORMANCE_MONITORING,
            "performanceSampleRate": self.PERFORMANCE_SAMPLE_RATE,
            "notificationsEnabled": self.NOTIFICATIONS_ENABLED,
        }
    
    def to_dict(self) -> Dict[str, Any]:
        """转换为字典"""
        return {
            key: str(value) if isinstance(value, Path) else value
            for key, value in self.dict().items()
            if not key.startswith("_") and key.isupper()
        }
    
    class Config:
        """Pydantic配置"""
        env_file = ".env"
        env_file_encoding = "utf-8"
        case_sensitive = True


def get_settings_by_environment(environment: str) -> Settings:
    """根据环境获取配置 ⚙️
    
    Args:
        environment: 环境名称 (development, production, testing)
        
    Returns:
        配置实例
    """
    settings = Settings(ENVIRONMENT=environment)
    
    # 根据环境调整配置
    if environment.lower() == "production":
        settings.DEBUG = False
        settings.RELOAD = False
        settings.WORKERS = max(os.cpu_count() or 1, 2)
        settings.LOG_LEVEL = "INFO"
        settings.PERFORMANCE_MONITORING = True
        settings.AUDIT_ENABLED = True
    elif environment.lower() == "testing":
        settings.DEBUG = True
        settings.DATABASE_URL = "sqlite+aiosqlite:///:memory:"
        settings.LOG_LEVEL = "DEBUG"
        settings.PERFORMANCE_MONITORING = False
        settings.AUDIT_ENABLED = False
    else:  # development
        settings.DEBUG = True
        settings.LOG_LEVEL = "DEBUG"
        settings.PERFORMANCE_MONITORING = False
    
    return settings


@lru_cache()
def get_settings() -> Settings:
    """获取配置单例 ⚙️

    Returns:
        配置实例
    """
    return Settings()


# 导出配置
settings = get_settings()


# 导出所有公共变量
__all__ = [
    'settings',
    'get_settings',
    'get_settings_by_environment',
    'Settings',
]